﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Threading;
using GA.Server.Configuration;
using System.Threading;
using log4net;

namespace GA.Server.Api
{
    public abstract class GAServer : DispatcherObject
    {
        /// <summary>
        /// Gets the name of the Server.
        /// </summary>
        public virtual string Name { get { return GetType().Name; } }

        /// <summary>
        /// Gets or sets the status of the server.
        /// </summary>
        public GAServerStatus Status { get; protected set; }

        /// <summary>
        /// Gets or sets the thread this server was spawned on.
        /// </summary>
        public Thread Thread { get; set; }

        /// <summary>
        /// Gets the unique process id associated with this server.
        /// </summary>
        public int ProcessId { get; private set; }

        /// <summary>
        /// Gets the started date of this process.
        /// </summary>
        public DateTime StartedDate { get; private set; }

        /// <summary>
        /// Gets the attached properties for this server.
        /// </summary>
        public ServerPropertiesElementCollection Properties { get; private set; }

        /// <summary>
        /// Constructor for GAServer that accepts properties.
        /// </summary>
        /// <param name="properties">ServerPropertiesElementCollection that represents the properties.</param>
        public GAServer(ServerPropertiesElementCollection properties)
        {
            Status = GAServerStatus.NotInitialized;
            ProcessId = sCurrentProcessId++;
            Properties = properties;
            Log = LogManager.GetLogger(GetType().FullName);
        }

        /// <summary>
        /// Default constructor for GAServer.
        /// </summary>
        public GAServer()
        {
            Status = GAServerStatus.NotInitialized;
            ProcessId = sCurrentProcessId++;
            Log = LogManager.GetLogger(GetType().FullName);
        }

        /// <summary>
        /// Notifies this server of another server starting up (or previously started and letting know of a server already running).
        /// </summary>
        /// <param name="newServer">GAServer that started.</param>
        public virtual void RegisterServer(GAServer newServer) { }

        /// <summary>
        /// Notifies this server of a server shutting down.
        /// </summary>
        /// <param name="killedServer">GAServer that stopped.</param>
        public virtual void DeregisterServer(GAServer killedServer) { }

        /// <summary>
        /// Starts a server. Should be performed on the same thread the object creation starts.
        /// </summary>
        public void Start()
        {
            Status = GAServerStatus.Starting;
            StartedDate = DateTime.Now;
            StartCore();
        }

        /// <summary>
        /// Stops a server.
        /// </summary>
        /// <param name="forceStop">If true, will force stop the server by ending the thread.</param>
        public void Stop(bool forceStop)
        {
            StopProcess = true;
            ForceStopProcess = forceStop;
        }

        /// <summary>
        /// Starts the core running.
        /// </summary>
        /// <remarks>This should execute the startup information and begin looping until the server is told to stop.</remarks>
        protected virtual void StartCore()
        {
            Log.InfoFormat("Server {0} started.", GetType().Name);
            Status = GAServerStatus.Running;
            while (!StopProcess)
            {
                Thread.Sleep(50);
            }
            Status = GAServerStatus.ShuttingDown;
            Status = GAServerStatus.Stopped;
        }

        /// <summary>
        /// Gets if the process should stop.
        /// </summary>
        protected bool StopProcess { get; private set; }

        /// <summary>
        /// Gets if the server should be force stopped. fs
        /// </summary>
        protected bool ForceStopProcess { get; private set; }

        /// <summary>
        /// Gets the Log assocated with the server.
        /// </summary>
        protected ILog Log { get; private set; }

        private static int sCurrentProcessId = 0;
    }
}
